#ifndef PhysicsHelper_H_
#define PhysicsHelper_H_

class PhysicsHelper
{
public:
	PhysicsHelper();
	~PhysicsHelper();

	inline static Ogre::Vector3 toOgre(const NxVec3 &vec)
	{
		return Ogre::Vector3(vec.x, vec.y, vec.z);
	}

	inline static Ogre::Quaternion toOgre(const NxQuat &qt)
	{
		return Ogre::Quaternion(qt.w, qt.x, qt.y, qt.z);
	}

	inline static NxVec3 toNX(const Ogre::Vector3 &vec)
	{
		return NxVec3(vec.x, vec.y, vec.z);
	}

	inline static NxQuat toNX(const Ogre::Quaternion &qt)
	{
		NxQuat nq;
		nq.setXYZW(qt.x,qt.y,qt.z,qt.w);
		return nq;
	}

	static float clamp (float value, float lowerLimit, float upperLimit)
	{
		if (value < lowerLimit){ return lowerLimit; }
		else if (value > upperLimit){ return upperLimit; }
		else { return value; }
	}
	inline static float RandFloat(){return ((rand())/(RAND_MAX+1.0));}
	inline static float RandInRange(float x, float y)
	{
		return x + RandFloat()*(y-x);
	}

	static void getMeshInformation(Ogre::Mesh* const mesh,
										 float* &vertices,
							   unsigned int &vertex_count,
								            int* &indices,
								unsigned int &index_count,
									      float* &normals,
							   unsigned short* &materials,
										      float* &min,
										      float* &max,
								   Ogre::Vector3 position = Ogre::Vector3::ZERO,
								  Ogre::Quaternion orient = Ogre::Quaternion::IDENTITY,
								      Ogre::Vector3 scale = Ogre::Vector3(1,1,1));
};

#define isnan( x ) (( x ) !=  ( x ))

#include "NxCharacter.h"
#include "NxController.h"
#include "NxCapsuleController.h"

enum CollGroup
{
	GROUP_NON_COLLIDABLE,
	GROUP_COLLIDABLE_NON_PUSHABLE,
	GROUP_COLLIDABLE_PUSHABLE,
};

#define COLLIDABLE_MASK	(1<<GROUP_COLLIDABLE_NON_PUSHABLE) | (1<<GROUP_COLLIDABLE_PUSHABLE)

class ControllerAllocator : public NxUserAllocator 
{
public:
	virtual void*   mallocDEBUG(size_t size, const char* fileName, int line)    { return ::malloc(size); }
	virtual void*   malloc(size_t size)                                         { return ::malloc(size); }
	virtual void*   realloc(void* memory, size_t size)                          { return ::realloc(memory, size); }
	virtual void    free(void* memory)                                          { ::free(memory); }
};

class ControllerHitReport : public NxUserControllerHitReport
{
	public:
	virtual NxControllerAction onShapeHit(const NxControllerShapeHit& hit)
	{
		if (1 && hit.shape)
		{
			NxCollisionGroup group = hit.shape->getGroup();
			if (group == GROUP_COLLIDABLE_PUSHABLE)
			{
				NxActor& actor = hit.shape->getActor();
				if(actor.isDynamic())
				{
					if(hit.dir.y==0.0f)
					{
						NxF32 coeff = hit.length * 64.0f;
						actor.addForceAtLocalPos(hit.dir*coeff, NxVec3(0,0,0), NX_IMPULSE);
					}
				}
			}
			else if(group==GROUP_COLLIDABLE_NON_PUSHABLE)
			{
			}
		}
		return NX_ACTION_NONE;
	}

	virtual NxControllerAction onControllerHit(const NxControllersHit& hit)
	{
		return NX_ACTION_NONE;
	}

};

#endif